$MOD186
Name Serial

; Serial routines for 8088 microcomputer system
;
; Filename:	Serial.ASM
;
; Author: 	Law Wen Yong
;
; This file contains proprietory information and cannot be copied 
; or distributed without prior permission from the author.
;---------------------------------------------------------------------------
;API:
;API:
;for debug purposes
public print_char ;transmit char to hyperterminal. Parameter is AL
public print_2hex ;to convert integer type into Ascii characters before transmitting to hyperterminal for display.  Parameter is AL

;initialisation
public Serial_initialise ;initialise serial settings
public SERIAL_INTR ;Serial transmit/receive interrupt routine


public Serial_reinitialise ;reinitialise serial settings variable


public Serial_check_if_server_active ; parameter AL 1-for active 0-for not active


;Received data
public Serial_check_Received_status ;return parameter AL: Serial_Received_status , AH: Type of data to received; 
public Serial_Get_data ;get data from serial. Parameter DI - offset address you want to copy to, ES - segment address you want to copy to

;sent data ;SI- for data input data ;ES - for data segment
public Serial_send_protocol ; use to transmit protocol. ;parameter AL-state

;transmit data
public Serial_check_Tbuffer_status ;return parameter AL; 0 means free 



Serial_DS SEGMENT
	Board_ID equ 01H
	Serial_Received_status DB Serial_no_data_in_RBuffer
	
	;Recieved Status:
	Type_of_Data_received DB 0H ;initial no message received
	Serial_Received_State DB Serial_wait_for_poll
	Serial_Unstuff_mode DB 0H
	
	;send status:
	Serial_Tbuffer_status DB Serial_Tbuffer_free
	Serial_Transmit_state DB Serial_not_transmitting
	
	
	;server active status
	Serial_active_status DB Serial_Not_Active
	
	;
	Serial_Type_1_serial_observed DB Serial_T1_not_observed
	
	
	;Sent Items
	
	Type_4_protocol DB 3,7EH,Board_ID,04H,'!',7FH ;acknowledge by client
	Type_1F_protocol DB 6,7EH,Board_ID,1FH,?,?,?,?,7FH ;AuthenticationState
	Type_15_3F_5F_75_7F_8F_protocol DB 2,7EH, Board_ID,?,7FH
	Type_25_45_protocol DB 8,7EH,Board_ID,?,4 DUP(?), 2 DUP(?),7FH
	Type_65_protocol DB 6,7EH,Board_ID,65H,4 DUP(?),7FH
	
	
	
	
Serial_DS ENDS


Received_buffer SEGMENT
    RBuffer_LEN	EQU	128 ;size of the queue ;about 128 bytes (note that this value is constant)

    RBuffer_TRANS	DB	RBuffer_LEN DUP(?) ;create the array of the queue according to this length
	RBuffer_HEAD	DW	0H ;index of the head in the array
	RBuffer_TAIL	DW	0H ;index of the tail in the array
	;RBuffer_cur_size DB 0H

Received_buffer ENDS

RBuffer_BASE	EQU	OFFSET RBuffer_TRANS 

;Queue for transmiting the serial data
;This queue is a circular array/buffer for storing data temporary before 
;transmision
;For the function below, it will do this:
;if there is something in the queue, the transmission interrupt will be 
;enable
;each time when the transmission holding register is empty , a 
;transmission interrupt will occured and
;it will extract from the head of the queue into the transmission holding 
;register
;if everything in the queue has been transmitted, the transmission 
;interrupt will be disabled
INT_RAM_AREA	SEGMENT
	QUEUE_LEN	EQU	40 ;size of the queue ;about 128 bytes (note that this value is constant)

	QUEUE_TRANS	DB	QUEUE_LEN DUP(?) ;create the array of the queue according to this length
	QUEUE_HEAD	DW	0H ;index of the head in the array
	QUEUE_TAIL	DW	0H ;index of the tail in the array
INT_RAM_AREA	ENDS

QUE_BASE	EQU	OFFSET QUEUE_TRANS  ;defined in the orignal code

$include(80188.inc)
$include(Serial.inc)


Serial_Routine SEGMENT
ASSUME CS:Serial_Routine



Serial_initialise PROC FAR

	   push AX
	   push DX
;Settings of the serial port transmission
;1st bit set 1 to access the Divisor latch 
;2 stop bits, 8 data bits, no parity check
        SMD_DATA_DIV EQU    10000111B
 ; set two stop bits, 8 data bits as well set the DLAB to 1 so that you could change the divisor value
        MOV DX, SMD
        MOV AL, SMD_DATA_DIV  
        OUT DX, AL
 ;set the baud rate to 9600bps.  divisor value =8MHz/(9600*16) = 52
        MOV DX, DLL
        MOV AL, 52     
        OUT DX, AL
        MOV DX, DLM
        MOV AL, 0
        OUT DX, AL
		
;SET SERIAL PORT WORKING MODE ;set the DLAB to 1 so that you could access Receiver Buffer, Transmitter holding register and Interrupt Enable Register
         MOV DX, SMD
         MOV AL, SMD_DATA
         OUT DX, AL
; Enable serial interrupts
		MOV	AL,S_INT_ENA
		OUT	SIER,AL
; =============== INITIALIZATION OF INTERRUPT CONTROL UNIT =============
; Initialize ICU for operation
		
; Mask all interrupts except SCU
                ;disable TX interrupt,ENABLE RX.
		MOV	AL,1
		OUT	SIER,AL
		
		;initialised machine id
		;MOV BX, Serial_DS
		;MOV DS, BX
		;MOV BL, 81H
		;MOV DS:Board_ID, BL
		;MOV DI, offset Type_1_protocol
		;INC DI
		;MOV [DI],BL
		;MOV DI, offset Type_3_protocol
		;INC DI
		;MOV [DI],BL
	   pop DX
	   pop AX
		ret
Serial_initialise ENDP


Serial_reinitialise proc far
    cli
	push AX
	push ES
	
	
	
	Mov AX,Received_buffer
	Mov ES, AX
	Mov ES:RBuffer_HEAD,0
	Mov ES:RBuffer_TAIL,0
	
	Mov AX,Serial_DS
	Mov ES, AX
	Mov ES:Serial_Received_status, Serial_no_data_in_RBuffer
	Mov ES:Type_of_Data_received, 0
	Mov ES:Serial_Received_State, Serial_wait_for_poll
	Mov ES:Serial_Unstuff_mode, 0

	
	
	
	pop ES
	pop AX
	sti
	ret
Serial_reinitialise endp


;check serial transmit status 
;parameter AL
Serial_check_Tbuffer_status proc far
	cli
	push DS
	push BX
	
	mov BX, Serial_DS
	mov DS, BX
	mov AL, DS:Serial_Tbuffer_status
	
	
	pop BX
	pop DS
	sti
	ret
Serial_check_Tbuffer_status endp


Serial_check_if_server_active PROC FAR
	cli
	Push DS
	Push BX
	
	Mov BX,Serial_DS
	Mov DS,BX
	
	Mov AL, DS:serial_active_status
	Mov DS:Serial_active_status, Serial_Not_Active
	
	POP BX
	POP DS
	sti
	ret
	
Serial_check_if_server_active endp

;parameter AL-state parameter; SI for data address
;ES
Serial_send_protocol proc far
	push DS
	push BX
	push CX
	
	Mov BX, Serial_DS
	Mov DS, BX
	
	
	
	
	cmp AL,4
	je Serial_send_normal
	

	Serial_Tbuffer_wait:
	cli
	
	cmp DS:Serial_Tbuffer_status,Serial_Tbuffer_free
	
	jne Serial_Tbuffer_enable
	
	
	
	mov DS:Serial_Tbuffer_status,Serial_Tbuffer_copying
	sti
	call far ptr Serial_copy_userdata_to_protocol
	
	jmp Serial_send_normal1
	Serial_Tbuffer_enable:
	sti
	jmp Serial_Tbuffer_wait
	
	Serial_send_normal:
	
	mov DS:Serial_Tbuffer_status,Serial_Tbuffer_copying
	
	Serial_send_normal1:
	
	
	
	;check if Tbuffer is free
	
	
	push SI
	
	


	
	
	
	;check if AL is 4
	cmp AL, 4
	jne Serial_check_protocol_1F ;AL contains invalid type
	;if AL is 4,
	;mov type 4 to SI
	Mov SI, offset Type_4_protocol
	jmp Serial_protocol_send_now
		
	Serial_check_protocol_1F:
	cmp AL, 1FH
	jne Serial_check_protocol_65
	;if AL==1F
	Mov SI, offset Type_1F_protocol
	jmp Serial_protocol_send_now
	
	
	Serial_check_protocol_65:
	cmp AL, 65H
	jne Serial_check_protocol_15
	Mov SI, offset Type_65_protocol
	jmp Serial_protocol_send_now
	
		
	Serial_check_protocol_15:
	cmp AL, 15H
	jne Serial_check_protocol_3F
	;if AL==15H
	jmp Serial_check_assign_15_3F_5F_75_7F_8F
	
	Serial_check_protocol_3F:
	cmp AL,3FH
	jne Serial_check_protocol_5F
	;if AL==3FH
	jmp Serial_check_assign_15_3F_5F_75_7F_8F
	
	Serial_check_protocol_5F:
	cmp AL,5FH
	jne Serial_check_protocol_75
	;if AL==5FH
	jmp Serial_check_assign_15_3F_5F_75_7F_8F
	
	Serial_check_protocol_75:
	cmp AL,75H
	jne Serial_check_protocol_7F
	;if AL==75H
	jmp Serial_check_assign_15_3F_5F_75_7F_8F
	
	Serial_check_protocol_7F:
	cmp AL, 7FH
	jne Serial_check_protocol_8F
	;if AL == 7FH
	jmp Serial_check_assign_15_3F_5F_75_7F_8F
	
	Serial_check_protocol_8F:
	cmp AL, 8FH
	jne Serial_check_protocol_25
	jmp Serial_check_assign_15_3F_5F_75_7F_8F
	
	Serial_check_protocol_25:
	cmp AL,25H
	jne Serial_check_protocol_45
	;if AL==25H
	jmp Serial_check_assign_25_45
	
	Serial_check_protocol_45:
	cmp AL,45H
	jne Serial_check_protocol_exit1
	;if AL==45H
	jmp Serial_check_assign_25_45
		
	Serial_check_protocol_exit1:
	cli
	Mov DS:Serial_Tbuffer_status, Serial_Tbuffer_free
	sti
	
	jmp Serial_check_protocol_exit
	
	Serial_check_assign_15_3F_5F_75_7F_8F:
	Mov SI, offset Type_15_3F_5F_75_7F_8F_protocol
	jmp Serial_check_assign_Type
	
	Serial_check_assign_25_45:
	Mov SI, offset Type_25_45_protocol
	
		
	Serial_check_assign_Type:
	Mov [SI+3],AL
		
	Serial_protocol_send_now:
	;Mov size to cx
	

	Mov CL, [SI]
	MOV CH, 0
	inc SI
	
	Mov AL,[SI]
	call far ptr print_char
	
	inc SI
	
	
	
	Serial_protocol_sending_loop:
	;check if the content needs byte stuffing
	
	Mov AL,[SI]
	cmp AL, 7DH
	jne Serial_protocol_check_7E
	;if AL is 7D
	push AX
	mov AL, 7DH
	call far ptr print_char
	pop AX
	
	xor AL, 20H
	
	jmp Serial_protocol_loop_end
	
	Serial_protocol_check_7E:
	cmp AL, 7EH
	jne Serial_protocol_check_7F
	
	
	push AX
	mov AL, 7DH
	call far ptr print_char
	pop AX
	
	xor AL, 20H
	
	Serial_protocol_check_7F:
	cmp AL, 7FH
	jne Serial_protocol_loop_end
	
	
	push AX
	mov AL, 7DH
	call far ptr print_char
	pop AX
	
	xor AL, 20H
	
	
	
	
	Serial_protocol_loop_end:
	
	
	
	call far ptr print_char
	
	inc SI
	loop Serial_protocol_sending_loop
	
	Mov AL,[SI]
	call far ptr print_char
	
	cli
	cmp DS:Serial_Transmit_state, Serial_transmitting
	jne Serial_check_normal
	push AX
	IN	AL,SIER			;enable TX interrupt after enqueuing to enable transmission to occur
	OR	AL,00000010B
	OUT	SIER,AL
	pop AX
	Serial_check_normal:
	Mov DS:Serial_Tbuffer_status,Serial_Tbuffer_full
	sti
	;set state to Tbuffer full
	;cli
	
	;sti
	
	Serial_check_protocol_exit:
	;sti
	
	
	pop SI
	pop CX
	pop BX
	pop DS
	ret
Serial_send_protocol endp


;parameter ES and SI
Serial_copy_userdata_to_protocol proc far
	push CX
	push BX
	push DI
	
	;check the type
	cmp AL,1FH
	jne Serial_copy_check_Type_25
	;if Type = 1FH
	mov DI, offset Type_1F_protocol
	
	jmp Serial_copy_userdata
	Serial_copy_check_Type_25:
	cmp AL,25H
	jne Serial_copy_check_Type_45
	;if Type = 25H
	jmp Serial_copy_assign_25_45
	
	Serial_copy_check_Type_45:
	cmp AL,45H
	jne Serial_copy_check_Type_65	
	jmp Serial_copy_assign_25_45
	
	Serial_copy_check_Type_65:
	cmp AL,65H
	jne Serial_copy_exit
	
	mov DI, offset Type_65_protocol
		
	jmp Serial_copy_userdata
	
	Serial_copy_assign_25_45:
	mov DI, offset Type_25_45_protocol
	
	
	
	
	Serial_copy_userdata:
	Mov CH,0
	Mov CL, DS:[DI]
	sub CL,2
	add DI, 4
	
	Serial_copy_userdata_loop:
	Mov BL,ES:[SI]
	Mov DS:[DI], BL
	
	inc DI
	inc SI
	loop Serial_copy_userdata_loop
		
	
	
	Serial_copy_exit:
	pop DI
	pop BX
	pop CX
	
	ret

Serial_copy_userdata_to_protocol endp


; ----------------Start of procedure PRINT_2HEX ------------------------
PRINT_2HEX 	PROC	FAR 
	
; The byte to be printed as 2 HEX number is put into AL.
; This procedure is then called.
		CALL	FAR PTR CHAR2HEX
; Result is return in AX
		PUSH 	AX  ;the hexadecimal digit in ascii is now stored in AX. push it into the stack now
		MOV	AL,AH   ;move the upper digit to AL
		CALL	FAR PTR PRINT_CHAR  ; transmit the upper digit
		POP	AX                ;now AL contains lower digit
		CALL	FAR PTR PRINT_CHAR ;transmit the lower digit
		RET
PRINT_2HEX	ENDP


;------------------Start of Procedure CHAR2HEX ----------------------------
CHAR2HEX	PROC	FAR 
; Char to be converted to HEX is put in AL before calling this procedure.
; HEX version is return in AX.
		MOV	AH,AL         ;store the full integer into AH
		AND	AL,00001111B  ;mov the lower part of the digit to AL
		CMP	AL,9          
		JG	GT9_1         ;check if more than 9
		OR	AL,00110000B  ;print as digit hexi. zero starts from 30H for ascii
		JMP 	DIGIT2
GT9_1:		SUB	AL,9       ;if more than 9, print as alphabets ascii. 
		OR	AL,01000000B  ;A starts from 41H for ascii
DIGIT2:
		SHR	AH,4          ;shift to right by 4. AH now has the upper digit
		CMP	AH,9          
		JG	GT9_2		 ;check if more than 9
		OR	AH,00110000B  ;print as digit hexi. zero starts from 30H for ascii
		JMP	DONE
GT9_2:		SUB	AH,9
		OR	AH,01000000B  ;A starts from 41H 
DONE:
		RET
CHAR2HEX	ENDP



; ---------------- Start of procedure PRINT_CHAR ------------------------
PRINT_CHAR	PROC	FAR
; This procedure is called to put a character into queue for transmission
; through the serial port. 
; The data to be transmitted is put in AL before the procedure is called.
; Data is put at the tail. Queue_tail is then inc to point to next loc.
; Data is taken from the head. Queue_head is then inc to point to next data.
	
		PUSH	BX			;Save BX	
		PUSH	ES

		;PUSH	AX

		MOV	BX,SEG QUEUE_TAIL	;Init segment register.  ;from the original code. another of putting Int_RAM_AREA into ES
		MOV	ES,BX			;ES now contains seg of INT_RAM_AREA
        cli
		;push ES
		
		;Mov BX, Serial_DS
		;Mov ES, BX
		
		;cmp ES:Serial_Transmit_state, Serial_transmitting
		;jne Serial_print_continue_normal
		;IN	AL,SIER 		;disable TX interrupt. ;to prevent the queue to be modified by the transmission interrupt when enqueuing is being done
		;AND	AL,11111101B    
		;OUT	SIER,AL
		
		
		Serial_print_continue_normal:
		
		;pop ES
		
		;POP	AX
		MOV	BX,ES:QUEUE_TAIL	;get the index of the tail
		MOV	ES:QUE_BASE[BX],AL	;Put data to queue_tail.
		INC	ES:QUEUE_TAIL		;Increment queue_tail
		CMP	ES:QUEUE_TAIL,QUEUE_LEN	;and wrap around
		JB	L_PRINT1		;to zero if needed.
		MOV	ES:QUEUE_TAIL,0
		
		
L_PRINT1:	
	
		;Mov BX, Serial_DS
		;Mov ES, BX
		
		;cmp ES:Serial_Transmit_state, Serial_transmitting
		;jne Serial_print_char_exit
		;push AX
		;IN	AL,SIER			;enable TX interrupt after enqueuing to enable transmission to occur
		;OR	AL,00000010B
		;OUT	SIER,AL
     	;pop AX
		
Serial_print_char_exit:
        sti
		POP	ES
		POP	BX
		RET
PRINT_CHAR	ENDP



SERIAL_REC_ACTION	PROC	FAR ;AL is the received byte
		PUSH	CX
		PUSH 	BX
		PUSH	DS
 
 
		
		Mov BX, Serial_DS
		Mov DS,BX
		Mov DS:Serial_active_status, Serial_Active
		
		
		Mov BL, DS:Serial_Received_state
		
		;if polling state,
		cmp BL, Serial_wait_for_poll
		jne Serial_check_for_other_rstate1
		;check if AL is 7E
		cmp AL,7EH
		JNE SR_exit1
		;if AL is 7E ;set state to check ID
		MOV BL, Serial_check_ID_state
		MOV DS:Serial_Received_state, BL
		
		SR_exit1:
		
		JMP SR_exit2
				
		Serial_check_for_other_rstate1:
		;check if it is in serial check ID state
		cmp BL, Serial_check_ID_state
		jne Serial_check_for_other_rstate2
		;if check ID state,
		;check if AL is 7D
		
		cmp AL,7DH
		jne Serial_checking_if_unstuff_needed
		
		;if AL is 7D
		;set to Unstuff mode so that the next byte will be unstuff
		Mov BL, 1H
		mov DS:Serial_Unstuff_mode, BL
		jmp SR_exit2
		
		Serial_checking_if_unstuff_needed:
		;else check if unstuffing needed
		Mov BL, DS:Serial_Unstuff_mode
		cmp BL, 1
		jne Serial_checking_ID
		;if byte unstuffing needed, xor with 20H
		xor AL, 20H
		;disable serial unstuff_mode
		MOV BL,0H
		Mov DS:Serial_Unstuff_mode, BL
		
		
		
		Serial_checking_ID:
		
		;check if this ID is mine
		cmp AL, Board_ID
		jne serial_not_my_ID
		;if this ID is mine
		;set state to Receving state
		Mov BL, Serial_check_Type_state
		Mov DS:Serial_Received_State,BL
		
		;set state to Serial transmitting
		Mov DS:Serial_Transmit_state, Serial_transmitting

		
		
		
		
		
		
		serial_not_my_ID:
		
		;if this ID is not mine:
		;set state to wait for others state
		Mov BL, Serial_wait_for_poll
		Mov DS:Serial_Received_State, BL
		SR_exit2:
		jmp SR_exit3
		
		Serial_check_for_other_rstate2:
		
		cmp BL, Serial_check_Type_state
		jne Serial_check_for_other_rstate3
		;if it is in Serial_check_Type_state
		cmp AL, 1H
		jne Serial_check_Type_continue
		Mov DS:Serial_Type_1_serial_observed, Serial_T1_is_observed
		
		
		Serial_check_Type_continue:
		Mov DS:Serial_Received_State, Serial_Receiving
		Mov BL, Serial_Receiving
		
		
		Serial_check_for_other_rstate3:
		
		;check if it is in Serial_Receiving state
		cmp BL, Serial_Receiving
		jne SR_exit3
		;if it is in Serial_Receiving state
		;check if AL is 7D
		cmp AL, 7DH
		jne Serial_check_if_finished_receiving
		
		;activate byte stuffing for next byte
		Mov BL, 1
		Mov DS:Serial_Unstuff_mode, BL
		jmp SR_exit3
		
			

		Serial_check_if_finished_receiving:
		cmp AL,7FH
		jne Serial_check_unstuffing2
		;if finished receiving
		;set state to wait for polling
		;set Serial_Received_status to Serial_has_packet_in_RBuffer 
		;change AL to 10 to indicate end of the packet and in the buffer
		;check_if this is type 1
		
		
				;if check Serial_Tbuffer is full
		cmp DS:Serial_Tbuffer_status, Serial_Tbuffer_full
		jne check_if_serial_empty
		
		push AX
		IN	AL,SIER			;enable TX interrupt 
		OR	AL,00000010B
		OUT	SIER,AL
		pop AX
		
		jmp SR_continue_finalised
		check_if_serial_empty:		
		cmp DS:Serial_Tbuffer_status, Serial_Tbuffer_free
		jne SR_exit2
		;if Tbuffer is empty, transmit type 4
		Mov AL, 4
		call far ptr Serial_send_protocol
		
		jmp SR_continue_finalised
		
		
		
		SR_continue_finalised:
		
		
		
		cmp DS:Serial_Type_1_serial_observed, Serial_T1_is_observed
		je Serial_check_change_poll
		Mov BL, Serial_has_packet_in_RBuffer 
		Mov DS:Serial_Received_status,BL
					
	    Serial_check_change_poll:	
		Mov BL, Serial_wait_for_poll
		Mov DS:Serial_Received_State,BL
		
		Mov DS:Serial_Type_1_serial_observed, Serial_T1_not_observed

		
		
		
		
		

		
		
		SR_exit3:
		JMP SR_exit
		
		
		
		
		Serial_check_unstuffing2:
		;check if byte unstuffing is needed
		Mov BL, DS:Serial_Unstuff_mode
		cmp BL, 1
		jne Serial_stored_msg_in_buffer
		
		;if unstuffing mode is activated,
		xor AL, 20H
		Mov BL, 0H
		Mov DS:Serial_Unstuff_mode, BL
		
				
		Serial_stored_msg_in_buffer:
		Mov BX,Serial_DS
		Mov DS, BX
		;cmp DS:Serial_received_status,Serial_has_packet_in_RBuffer
		;je SR_exit
		cmp DS:Serial_Type_1_serial_observed, Serial_T1_is_observed
		je SR_exit
		
		
		MOV BX, Received_buffer
		MOV DS, BX
		MOV BX,DS:RBuffer_TAIL           
		MOV DS:RBuffer_BASE[BX],AL     ;saved the received byte into the buffer
		INC DS:RBuffer_TAIL
		;INC DS:RBuffer_cur_Size ;increase cur buffer size
		CMP DS:RBuffer_TAIL, RBuffer_LEN
		JB SR_exit
		MOV DS:RBuffer_TAIL,0

		
		
SR_exit:
		
		POP	DS
		POP	BX
		POP	CX
		RET
SERIAL_REC_ACTION	ENDP






; ************************************************************************
;			INTERRUPT ROUTINES				 *
; ************************************************************************

; **************** Start of SERIAL_INTR service routine ******************

;*****************CAUTION*****************
;At the end of interrutp routines, you must write EOI (end of Int) +
;with the INT type (INT0-type 12) 		   +	
;comment added by Zhu Shunyu	March,2000			   +				
;Interrupt Routines Modified accordly to fit 80C188XL
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
SERIAL_INTR     proc Far

	PUSH    AX
	PUSH    BX
	PUSH    CX
	PUSH    DX
	PUSH    BP
	PUSH    SI
	PUSH    DI
	PUSH    DS
	PUSH    ES
	
	MOV 	AX, 0700H
	MOV 	ES, AX
	MOV 	DS, AX
	XOR    	AX, AX
	XOR    	BX, BX
	XOR    	CX, CX
	XOR    	DX, DX
	XOR    	BP, BP
	XOR    	SI, SI
	XOR    	DI, DI
    call far ptr SERIAL_ISR 
	
	MOV DX, EOI ;end of interrupt needed for all end of the interrupt routine
    MOV AX, 12 ;send out type number 12
    OUT DX, AL
		   
	POP 	ES
	POP 	DS
	POP 	DI
	POP 	SI
	POP 	BP
	POP 	DX
	POP 	CX
	POP 	BX
	POP 	AX

	IRET
SERIAL_INTR ENDP


SERIAL_ISR    proc Far
		PUSH	AX			;save registers
		PUSH	BX
        PUSH    DX

		

       

               	               
		IN	AL,IIR			;read in serial INT ID
        AND     AL,00000111B
		CMP     AL,00000100B		;check if rx interrupt
		JE	RECEIVE_INTR

		CMP    	AL,00000010B		;check if tx interrupt
		JE	TRANSMIT_INTR

		
;RESET_INT_CTL  ;If it is not any of the transmision/receive interrupt 
;false serial interrupt:
;*****************************************************************



        POP DX
		POP	BX			
		POP	AX
		RET				;return
;**********************************************************************

RECEIVE_INTR:	
              
		IN	AL,SRB		;read in from receive buffer	
; Information received will be used by user routine
; Action to be taken will be contained in SERIAL_REC_ACTION
		CALL	FAR PTR SERIAL_REC_ACTION
		
		POP DX
		POP	BX			
		POP	AX
		RET

TRANSMIT_INTR:
               
		PUSH	ES			;save ES
		MOV	BX,SEG QUEUE_TAIL	;set ES to SERIAL_Q_SEG  ;from the original code. another of putting Int_RAM_AREA into ES
		MOV	ES,BX
		MOV	BX,ES:QUEUE_TAIL
		CMP	BX,ES:QUEUE_HEAD	;more data to be transmitted? 
		JE	L_TX2				;check if the tail index is same as head index
		MOV	BX,ES:QUEUE_HEAD	;get data from head of the queue
		MOV	AL,ES:QUE_BASE[BX]   
		OUT	STB,AL			;tx data by moving the data into STB
		INC	ES:QUEUE_HEAD		;point to next data ;increment the head because the element has been extracted out and put in STB
		CMP	ES:QUEUE_HEAD,QUEUE_LEN ;wrap around if necessary
		JB	L_TX1            
		MOV	ES:QUEUE_HEAD,0
L_TX1:		
		MOV	BX,ES:QUEUE_TAIL   
		CMP	BX,ES:QUEUE_HEAD	;more data to be transmitted?
		JNE	L_TX3
L_TX2:
		Mov AH, AL
		IN	AL,SIER			;no more, disable TX interrupt.
		AND    	AL,11111101B
		OUT	SIER,AL
		push BX
		push ES
		
		;cmp AH, 7FH
		;jne L_TX3
		;set Serial_transmit_state to Serial_not_transmitting
		Mov BX, Serial_DS
		MOV ES, BX
		MOV ES:Serial_Tbuffer_status, Serial_Tbuffer_free
		Mov ES:Serial_Transmit_state, Serial_not_transmitting
		pop ES
		pop BX
		
L_TX3:
		
      		POP	ES			;restore original ES(transmit)
		
                POP     DX 
                POP	BX			
		POP	AX
		RET
; **************** End of SERIAL_INTR service routine ************************

SERIAL_ISR ENDP

;return parameter AL: Serial_Received_status , AH: Type of data to received
Serial_check_Received_status proc Far
	
	push DS
	push BX
	Mov BX, Serial_DS
	Mov DS, BX
	Mov AL, DS:Serial_Received_status 
	
	cmp AL, Serial_has_packet_in_RBuffer
	je Serial_retrieve_type
	
	Mov AH, 0H  ;nothing
	jmp SCRS_exit
	Serial_retrieve_type:
	Mov Bx, Received_buffer
	
		
	Mov DS, BX
	Mov BX,DS:RBuffer_HEAD
	Mov AH, DS:RBuffer_BASE[BX] ;type of data
	
	SCRS_exit:
	pop BX
	pop DS
	
	ret
Serial_check_Received_status endp


Serial_Get_data proc Far ;get data from serial. Parameter DI - offset address you want to copy to, ES - segment address you want to copy to
  push DS
  push BX
  push AX
  cli
  MOV BX, Received_buffer
  MOV DS, BX
  
  MOV BX, DS:RBuffer_TAIL
  CMP BX, DS:RBuffer_HEAD
  JE serial_end2
  
  
  
  
  INC DS:RBuffer_HEAD
  ;DEC DS:RBuffer_cur_size
  
  CMP DS:RBuffer_HEAD, RBuffer_LEN
  
  JB Serial_RBuffer_loop
  MOV DS:RBuffer_HEAD,0
  
  
Serial_RBuffer_loop: 

  MOV BX, DS:RBuffer_TAIL
  CMP BX, DS:RBuffer_HEAD
  JE serial_end2
  
  MOV BX,DS:RBuffer_HEAD
  MOV AL,DS:RBuffer_BASE[BX]
  INC DS:RBuffer_HEAD
  ;DEC DS:RBuffer_cur_size
  
   

  
  ;cmp AL, 10
 ;JE serial_end2
  
  MOV ES:[DI], AL
  INC DI
 ; call far ptr print_2Hex
  
  CMP DS:RBuffer_HEAD, RBuffer_LEN
  
  JB dont_reset_head_to_zero
  MOV DS:RBuffer_HEAD,0
  
 dont_reset_head_to_zero:
  JMP Serial_RBuffer_loop
  
 serial_end2:

	MOV BX, Serial_DS 
	MOV DS, BX
	MOV AL, Serial_no_data_in_RBuffer
	MOV DS:Serial_Received_status ,AL
	
  
 
  pop AX
  pop BX
  pop DS
  sti
  ret
Serial_Get_data ENDP



Serial_ROUTINE	ENDS

End
